<?php

namespace Helpers;

class CurlClient{

    private $ch;
    private $baseUrl = '';
    private $headerOption = [];

    public $error;
    public $body;
    public $header;

    //初始化
    function __construct()
    {
        $this->ch = curl_init();
        //不自动输出
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->ch, CURLOPT_ENCODING, 'UTF-8');
    }

    //销毁
    function __destruct()
    {
        $this->headerOption = [];
        $this->body         = null;
        $this->header       = null;
        curl_close($this->ch);
    }

    //设置基础url
    public function setBaseUrl($baseUrl)
    {
        $this->baseUrl = $baseUrl;
        return $this;
    }

    //处理拼接基础url
    private function resolveUrl($url)
    {
        if(empty($this->baseUrl)) return $url;
        return $this->baseUrl;
//        return rtrim($this->baseUrl, '/ ') . '/' . ltrim($url, '/ ');
    }

    //设置curl属性
    public function setOption($option, $value)
    {
        @curl_setopt($this->ch, $option, $value);
        return $this;
    }

    //批量设置curl属性
    public function setOptions($options)
    {
        @curl_setopt_array($this->ch, $options);
        return $this;
    }

    //设置超时时间
    public function setTimeout($timeOut = 10)
    {
        $this->setOption(CURLOPT_TIMEOUT, $timeOut);
        return $this;
    }

    //设置连接超时时间
    public function setConnectTimeout($timeout = 2)
    {
        $this->setOption(CURLOPT_CONNECTTIMEOUT, $timeout);
        return $this;
    }

    //不返回Header
    public function disableHeader($disable = true)
    {
        $this->setOption(CURLOPT_HEADER, $disable);
        return $this;
    }

    //不返回Body
    public function disableBody($disable = true)
    {
        $this->setOption(CURLOPT_NOBODY, $disable);
        return $this;
    }

    //设置userAgent
    public function setUserAgent($userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36')
    {
        $this->setOption(CURLOPT_USERAGENT, $userAgent);
        return $this;
    }

    //设置http头属性
    public function setHeader($option, $value)
    {
        $this->headerOption[$option] = $value;
        return $this;
    }

    //批量设置http头属性
    public function setHeaders(array $options)
    {
        $this->headerOption = array_merge($this->headerOption, $options);
        return $this;
    }

    //删除http头属性
    public function removeHeader($name)
    {
        unset($this->headerOption[$name]);
        return $this;
    }

    //处理并设置http头
    private function resolveHeader()
    {
        if(!empty($this->headerOption)){
            $headerLine = [];
            foreach ($this->headerOption as $field => $value) {
                $headerLine[] = $field . ': ' . $value;
            }
            $this->setOption(CURLOPT_HTTPHEADER, $headerLine);
        }
    }

    //处理返回http头信息
    private function handleHeader()
    {
        $headInfo = new \stdClass();
        $headInfo->statusCode   = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
        $headInfo->contentType  = curl_getinfo($this->ch, CURLINFO_CONTENT_TYPE);
        $headInfo->requestUrl   = curl_getinfo($this->ch, CURLINFO_EFFECTIVE_URL);
        return $headInfo;
    }

    //检查http返回状态是否成功(2XX)
    public function checkStatus()
    {
        if(!isset($this->header->statusCode)) return false;
        $statusCode = $this->header->statusCode;
        return substr($statusCode, 0, 1) == 2 ? true : false;
    }

    //根据类型解析body
    public function decodeBody($type = 'json', $array = false)
    {
        if(!empty($this->body)){
            switch($type){
                case 'json': $this->body = json_decode($this->body, $array); break;
            }
        }
    }

    //处理post数据(put)
    private function initPostFields($params, $useEncoding)
    {
        if(is_array($params)){
            //有文件则不使用urlencode
            foreach($params as $param) {
                if((is_string($param) && strpos($param, '@') === 0) || ($param instanceof \CURLFile)) {
                    $useEncoding = false;
                    break;
                }
            }
            if($useEncoding) {
                $params = http_build_query($params);
            }
        }
        if(!empty($params)) {
            $this->setOption(CURLOPT_POSTFIELDS, $params);
        }
    }

    //执行curl，错误则返回错误原因
    private function execCurl()
    {
        $result = curl_exec($this->ch);
        if($result === false){
            $this->error = curl_error($this->ch);
        }
        return $result;
    }

    //清除记录
    public function clean()
    {
        $this->body   = null;
        $this->header = null;
        $this->error  = null;
    }

    /**
     * GET方式请求
     *
     * @param $url
     * @param array $params
     * @return $this
     *
     * create by ck 20170418
     */
    public function get($url=null, $params = [])
    {
        $this->clean();
        $url = $this->resolveUrl($url);
        if(!empty($params)){
            $url .= '?' . (is_array($params) ? http_build_query($params) : $params);
        }
        $this->resolveHeader();
        $this->setOptions([
            CURLOPT_URL           => $url,
            CURLOPT_HTTPGET       => true,
            CURLOPT_CUSTOMREQUEST => 'GET',
        ]);
        $this->body = $this->execCurl();
        $this->header = $this->handleHeader();
        return $this;
    }

    /**
     * POST方式请求
     *
     * @param $url
     * @param array $params
     * @param bool $useEncoding
     * @return $this
     *
     * create by ck 20170418
     */
    public function post($url=null, $params = [], $useEncoding = true)
    {
        $this->clean();
        $url = $this->resolveUrl($url);
        $this->resolveHeader();
        $this->setOptions([
            CURLOPT_URL             => $url,
            CURLOPT_POST            => true,
            CURLOPT_CUSTOMREQUEST   => 'POST',
        ]);
        $this->initPostFields($params, $useEncoding);

        $this->body = $this->execCurl();
        $this->header = $this->handleHeader();
        return $this;
    }

    /**
     * #方法说明： PUT方式
     * @param null $url
     * @param array $params
     * @param bool $useEncoding
     * @return $this
    # Created by zsc
     */
    public function json($url=null, $params = [], $useEncoding = false)
    {
        is_array($params) && $params = json_encode($params,JSON_UNESCAPED_UNICODE);
        $this->clean();
        $url = $this->resolveUrl($url);
        $this->setHeaders(array(
            'Content-Type'  => 'application/json; charset=utf-8',
            'Content-Length' => strlen($params),
        ));
        $this->resolveHeader();
        $this->setOptions([
            CURLOPT_URL             => $url,
        ]);
        $this->initPostFields($params, $useEncoding);
        $this->body = $this->execCurl();
        $this->header = $this->handleHeader();
        return $this;
    }




    /**
     * #方法说明： PUT方式
     * @param null $url
     * @param array $params
     * @param bool $useEncoding
     * @return $this
    # Created by zsc
     */
    public function put($url=null, $params = [], $useEncoding = false)
    {
        is_array($params) && $params = json_encode($params,JSON_UNESCAPED_UNICODE);
        $this->clean();
        $url = $this->resolveUrl($url);
        $this->setHeaders(array(
            'Content-Type'=>'application/json; charset=utf-8'
        ));
        $this->resolveHeader();
        $this->setOptions([
            CURLOPT_URL             => $url,
            CURLOPT_CUSTOMREQUEST   => "PUT",
        ]);
        $this->initPostFields($params, $useEncoding);
        $this->body = $this->execCurl();
        $this->header = $this->handleHeader();
        return $this;
    }


    /**
     * #方法说明：patch提交方式， 参数放入url提交
     * @param null $url
     * @param array $params
     * @param bool $useEncoding
     * @return $this
    # Created by zsc
     */
    public function patchQuery($url=null, $params = [], $useEncoding = true)
    {
        $this->clean();
        $url = $this->resolveUrl($url);
        $this->setHeaders(array(
            'Content-Type'=>'application/json; charset=utf-8'
        ));
        $url .= '?' . (is_array($params) ? http_build_query($params) : $params);
        $this->resolveHeader();
        $this->setOptions([
            CURLOPT_URL             => $url,
            CURLOPT_CUSTOMREQUEST   => "PATCH",
        ]);
        $this->initPostFields(array(), $useEncoding);;
        $this->body = $this->execCurl();
        $this->header = $this->handleHeader();
        return $this;
    }

    /**
     * #方法说明：参数放入body提交
     * @param null $url
     * @param array $params
     * @param bool $useEncoding
     * @return $this
    # Created by zsc
     */
    public function patchBody($url=null, $params = [], $useEncoding = true)
    {
        $this->clean();
        $url = $this->resolveUrl($url);
        $this->setHeaders(array(
            'Content-Type'=>'application/json; charset=utf-8'
        ));
        $this->resolveHeader();
        is_array($params) && $params = json_encode($params,JSON_UNESCAPED_UNICODE);
        $this->setOptions([
            CURLOPT_URL             => $url,
            CURLOPT_CUSTOMREQUEST   => "PATCH",
        ]);
        $this->initPostFields($params, $useEncoding);;
        $this->body = $this->execCurl();
        $this->header = $this->handleHeader();
        return $this;
    }



    /**
     * #方法说明：PATCH 方式
     * @param null $url
     * @param array $params
     * @param bool $useEncoding
     * @return $this
    # Created by zsc
     */
//    public function patch($url=null, $params = [], $useEncoding = true,$method='GET')
//    {
//        $this->clean();
//        $url = $this->resolveUrl($url);
//        $this->setHeaders(array(
//            'Content-Type'=>'application/json; charset=utf-8'
//        ));
//        if($method=='GET'){
//            $url .= '?' . (is_array($params) ? http_build_query($params) : $params);
//        }
//        $this->resolveHeader();
//        is_array($params) && $params = json_encode($params,JSON_UNESCAPED_UNICODE);
//        $this->setOptions([
//            CURLOPT_URL             => $url,
//            CURLOPT_CUSTOMREQUEST   => "PATCH",
//        ]);
//        $this->initPostFields($params, $useEncoding);;
//        $this->body = $this->execCurl();
//        $this->header = $this->handleHeader();
//        return $this;
//    }

    /**
     * DELETE方式请求
     *
     * @param $url
     * @param array $params
     * @return $this
     *
     * create by ck 20170419
     */
    public function delete($url=null, $params = [], $useEncoding = true)
    {

        $this->clean();
        $url = $this->resolveUrl($url);
        $this->setHeaders(array(
            'Content-Type'=>'application/json; charset=utf-8'
        ));
        if(!empty($params)){
            $url .= '?' . (is_array($params) ? http_build_query($params) : $params);
        }
        $params = array();
        $this->resolveHeader();
        $this->setOptions([
            CURLOPT_URL             => $url,
            CURLOPT_CUSTOMREQUEST   => 'DELETE',
        ]);
        $this->initPostFields($params, $useEncoding);;
        $this->body = $this->execCurl();
        $this->header = $this->handleHeader();
        return $this;
    }

    /**
     * #方法说明：获取头转换
     * @param string $type
     * @return array|bool|object|string
    # Created by zsc
     */
    public function headerConvert($type='array'){
        if(!empty($this->header)){
            switch($type){
                case 'array':return (array)$this->header; break;
                case 'object':return (object)$this->header; break;
                case 'json':return json_encode($this->header,JSON_UNESCAPED_UNICODE); break;
            }
        }
        return false;
    }

    /**
     * #方法说明：获取body转换
     * @param string $type
     * @return bool|mixed|string
    # Created by zsc
     */
    public function bodyConvert($type='array'){
        if(!empty($this->body)){
            switch($type){
                case 'array':return json_decode($this->body, true); break;
                case 'object':return json_decode($this->body); break;
                case 'json':return json_encode($this->body,JSON_UNESCAPED_UNICODE); break;
            }
        }
        return false;
    }

}